/* Copyright (c) 2024 Qualcomm Technologies International, Ltd. */
/* %%version */

#include "gatt_ots_client_discovery.h"
#include "gatt_ots_client_init.h"
#include "gatt_ots_client_uuid.h"
#include "gatt_ots_client_indication.h"

static void otscReadSupportedFeatures(GOTSC *gattOtsClient)
{
    CsrBtGattReadReqSend(gattOtsClient->srvcElem->gattId,
                         gattOtsClient->srvcElem->cid,
                         gattOtsClient->deviceData.otsFeatureHandle,
                         0);
    gattOtsClient->pendingCmd |= OTSC_PENDING_OP_READ_FEATURE_CHAR;
}

static void otscDiscoverAllCharacteristicDescriptors(GOTSC *gattOtsClient)
{
    CsrBtGattDiscoverAllCharacDescriptorsReqSend(gattOtsClient->srvcElem->gattId,
                                                 gattOtsClient->srvcElem->cid,
                                                 gattOtsClient->deviceData.startHandle + 1,
                                                 gattOtsClient->deviceData.endHandle);
}

void OtscRegisterForMandatoryIndications(GOTSC *gattOtsClient)
{
    uint8* oacpValue = (uint8*)(CsrPmemAlloc(GATT_OTS_CLIENT_CHARACTERISTIC_CONFIG_SIZE));

    oacpValue[0] = OTS_INDICATION_VALUE;
    oacpValue[1] = 0;

    /* Register for the mandatory control point indication */
    CsrBtGattWriteReqSend(gattOtsClient->srvcElem->gattId,
                          gattOtsClient->srvcElem->cid,
                          gattOtsClient->deviceData.objActionControlPointCCCDHandle,
                          0,
                          GATT_OTS_CLIENT_CHARACTERISTIC_CONFIG_SIZE,
                          oacpValue);

    gattOtsClient->pendingCmd |= OTSC_PENDING_OP_WRITE_OACP_CCCD;
}

void OtscHandleDiscoverCharacteristicsCfm(GOTSC *gattOtsClient,
                                          const GATT_MANAGER_DISCOVER_ALL_CHARACTERISTICS_CFM_T *cfm)
{
    GATT_OTS_CLIENT_INFO("GOTSC : DiscoverAllCharacteristics status=[%u] uuid=[0x%x] more=[%u]\n",
                          cfm->status,
                          cfm->uuid[0],
                          cfm->more_to_come);

    if (cfm->status == ATT_RESULT_SUCCESS)
    {
        if (cfm->uuid_type == ATT_UUID16)
        {
            switch (cfm->uuid[0])
            {
                case OTS_UUID_OTS_FEATURE:
                {
                    gattOtsClient->deviceData.otsFeatureHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: OTS Feature Handle [0x%x]\n ", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_NAME:
                {
                    gattOtsClient->deviceData.objNameHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object Name Handle [0x%x]\n", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_TYPE:
                {
                    gattOtsClient->deviceData.objTypeHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object Type Handle [0x%x]\n", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_SIZE:
                {
                    gattOtsClient->deviceData.objSizeHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object Size Handle [0x%x]\n", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_FIRST_CREATED:
                {
                    gattOtsClient->deviceData.objFirstCreatedHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object First Created Handle [0x%x]\n", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_LAST_MODIFIED:
                {
                    gattOtsClient->deviceData.objLastModifiedHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object Last Modified Handle [0x%x]\n", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_ID:
                {
                    gattOtsClient->deviceData.objIdHandle= cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object ID Handle [0x%x]\n ", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_PROPERTIES:
                {
                    gattOtsClient->deviceData.objPropertiesHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object Properties Handle [0x%x]\n ", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_ACTION_CONTROL_POINT:
                {
                    gattOtsClient->deviceData.objActionControlPointHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object Action Control Point Handle [0x%x]\n ", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_LIST_CONTROL_POINT:
                {
                    gattOtsClient->deviceData.objListControlPointHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object List Control Point Handle [0x%x]\n ", cfm->handle);
                    break;
                }

                case OTS_UUID_OBJECT_LIST_FILTER:
                {
                    if (gattOtsClient->deviceData.objListFilterHandle1 == 0)
                    {
                        gattOtsClient->deviceData.objListFilterHandle1 = cfm->handle;
                        GATT_OTS_CLIENT_INFO("GOTSC: Object List Filter Handle1 [0x%x]\n ", cfm->handle);
                    }
                    else if (gattOtsClient->deviceData.objListFilterHandle2 == 0)
                    {
                        gattOtsClient->deviceData.objListFilterHandle2 = cfm->handle;
                        GATT_OTS_CLIENT_INFO("GOTSC: Object List Filter Handle2 [0x%x]\n ", cfm->handle);
                    }
                    else
                    {
                        gattOtsClient->deviceData.objListFilterHandle3 = cfm->handle;
                        GATT_OTS_CLIENT_INFO("GOTSC: Object List Filter Handle3 [0x%x]\n ", cfm->handle);
                    }
                    break;
                }

                case OTS_UUID_OBJECT_CHANGED:
                {
                    gattOtsClient->deviceData.objChangedHandle = cfm->handle;
                    GATT_OTS_CLIENT_INFO("GOTSC: Object Changed Handle [0x%x]\n ", cfm->handle);
                    break;
                }

                default:
                {
                    GATT_OTS_CLIENT_ERROR("GOTSC: Unknown Handle [0x%x]\n ", cfm->handle);
                    break;
                }
            }
        }

        if (!cfm->more_to_come)
        {
            /* Check whether all mandatory characteristics are found */
            if (!gattOtsClient->deviceData.otsFeatureHandle    ||
                !gattOtsClient->deviceData.objNameHandle       ||
                !gattOtsClient->deviceData.objTypeHandle       ||
                !gattOtsClient->deviceData.objSizeHandle       ||
                !gattOtsClient->deviceData.objPropertiesHandle ||
                !gattOtsClient->deviceData.objActionControlPointHandle)
            {
                /* Fail the init procedure as all mandatory characteristics are not found */
                GattOtscSendInitCfm(gattOtsClient,
                                    GATT_OTSC_RESULT_CODE_OPERATION_FAILED,
                                    GATT_SUPPLIER_OTS_CLIENT);
            }
            else
            {
                /* All characteristics found, lets discover the descriptors now */
                otscDiscoverAllCharacteristicDescriptors(gattOtsClient);
            }
        }
    }
    else
    {
        GattOtscSendInitCfm(gattOtsClient,
                            GATT_OTSC_RESULT_CODE_OPERATION_FAILED,
                            GATT_SUPPLIER_OTS_CLIENT);
    }

}

void OtscHandleDiscoverCharacDescriptorsCfm(GOTSC *gattOtsClient,
                                            const GATT_MANAGER_DISCOVER_ALL_CHARACTERISTIC_DESCRIPTORS_CFM_T *cfm)
{
    GATT_OTS_CLIENT_INFO("GOTSC: DiscoverAllDescriptors status=[%u] uuid=[0x%x] more=[%u]\n",
                          cfm->status,
                          cfm->uuid[0],
                          cfm->more_to_come);

    if (cfm->status == ATT_RESULT_SUCCESS)
    {
        if (cfm->uuid_type == ATT_UUID16)
        {
            switch (cfm->uuid[0])
            {
                case OTS_UUID_OBJECT_ACTION_CONTROL_POINT:
                case OTS_UUID_OBJECT_LIST_CONTROL_POINT:
                case OTS_UUID_OBJECT_CHANGED:
                {
                    gattOtsClient->pendingHandle     = cfm->handle;
                    break;
                }

                case CSR_BT_GATT_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION_DESC:
                {
                    if (gattOtsClient->pendingHandle == gattOtsClient->deviceData.objActionControlPointHandle)
                    {
                        gattOtsClient->deviceData.objActionControlPointCCCDHandle = cfm->handle;
                        gattOtsClient->pendingHandle = 0;
                    }
                    else if (gattOtsClient->pendingHandle == gattOtsClient->deviceData.objListControlPointHandle)
                    {
                        gattOtsClient->deviceData.objListControlPointCCCDHandle = cfm->handle;
                        gattOtsClient->pendingHandle = 0;
                    }
                    else if (gattOtsClient->pendingHandle == gattOtsClient->deviceData.objChangedHandle)
                    {
                        gattOtsClient->deviceData.objChangedCCCDHandle = cfm->handle;
                        gattOtsClient->pendingHandle = 0;
                    }
                    else
                    {
                        /* Not expected to be here */
                    }
                    break;
                }

                default:
                {
                    break;
                }
            }
        }

        if (!cfm->more_to_come)
        {
            if ((!gattOtsClient->deviceData.objActionControlPointCCCDHandle) ||
                (gattOtsClient->deviceData.objListControlPointHandle &&
                 !gattOtsClient->deviceData.objListControlPointCCCDHandle))
            { /* One of the mandatory OTS characteristic's CCCD is not found, fail the initialization */
                GattOtscSendInitCfm(gattOtsClient,
                                    GATT_OTSC_RESULT_CODE_OPERATION_FAILED,
                                    GATT_SUPPLIER_OTS_CLIENT);
            }
            else
            {
                /* Read peer's supported features */
                otscReadSupportedFeatures(gattOtsClient);
            }
         }
    }
    else
    {
        GattOtscSendInitCfm(gattOtsClient, 
                            GATT_OTSC_RESULT_CODE_OPERATION_FAILED,
                            GATT_SUPPLIER_OTS_CLIENT);
    }
}

